package MainApplication;

import generalClasses.Coupon;
import generalClasses.CouponForQuery;
import generalClasses.GroupCoupon;
import generalClasses.ProgramData;
import generalClasses.PurchaseType;
import generalClasses.Server;
import generalClasses.User;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;

import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;

import org.dyno.visual.swing.layouts.GroupLayout;

import udpClient.ComercialThread;
import UIPanels.LocalPanel;
import UIPanels.LoginPanel;
import UIPanels.MainPanel;
import UIPanels.PurchaseHistoryPanel;
import UIPanels.Registration;
import UIPanels.UpdateUserDetails;
import client.control.ClientControl;
import client.protocols.LoginClientProtocol;
import client.protocols.PurchaseKuponClientProtocol;
import client.protocols.RegistrationClientProtocol;
import client.protocols.UpdateDetailsClientProtocol;

//VS4E -- DO NOT REMOVE THIS LINE!
public class MainApplication extends JFrame
{
	private static final long serialVersionUID = 1L;
	private static final String PREFERRED_LOOK_AND_FEEL = "javax.swing.plaf.metal.MetalLookAndFeel";
	
	private ClientControl clientControl;
	//Panel that display Login screen
	private LoginPanel login;
	//Panel that display Registration screen
	private Registration regPanel;
	//Panel that display Main Windows of application
	private static MainPanel mainPanel;
	//Panel that display update user details
	private	UpdateUserDetails updatePanel;
	//Panel that display Purchase History
	private static PurchaseHistoryPanel purchaseHistoryPanel;
	//Panel that display available coupons
	private static LocalPanel localPanel;
	
	//private MulticastClient commercials;
	private static ComercialThread commercials;

	private ProgramData pd; 
	private static User _originalUser = null;
	
	private static final boolean SINGLE_COUPON = false;
	private static final boolean GROUP_COUPON = true;
	
	private static final String CLIENT_DISCONNECTED_ERROR_MESSAGE = "Your machine cannot reach default gateway !\nFix the problem and start application again later";
	
	private static Server correntRegionServer;
//	//Variables to prevent clicking on a button runs more times that needed
//	private static int startLocalPanelNorthEntranceCounter = 0;
//	private static int startLocalPanelNorthDisplayCounter = 0;
//	private static int startLocalPanelSouthEntranceCounter = 0;
//	private static int startLocalPanelSouthDisplayCounter = 0;
//	private static int startLocalPanelCenterEntranceCounter = 0;
//	private static int startLocalPanelCenterDisplayCounter = 0;
//	private static int startLocalPanelGeneralEntranceCounter = 0;
//	private static int startLocalPanelGeneralDisplayCounter = 0;
//	private static int startHistoryPanelEntranceCounter = 0;
//	private static int startHistoryPanelDisplayCounter = 0;
//	private String temp;
	
	public MainApplication()
	{
		initComponents();
	}

	private void initComponents() 
	{
		setLayout(new GroupLayout());
		setSize(500, 400);
		
		// Initiate all Panels
		clientControl = new ClientControl();
		login = new LoginPanel();
		regPanel = new Registration();
		mainPanel = new MainPanel();
		updatePanel = new UpdateUserDetails();
		pd = new ProgramData();
	}

	private static void installLnF()
	{
		try
		{
			String lnfClassname = PREFERRED_LOOK_AND_FEEL;
			if ( lnfClassname == null )
				lnfClassname = UIManager.getCrossPlatformLookAndFeelClassName();
			UIManager.setLookAndFeel(lnfClassname);
		}
		catch (Exception e)
		{
			System.err.println("Cannot install " + PREFERRED_LOOK_AND_FEEL
					+ " on this platform:" + e.getMessage());
		}
	}
	
	/**
	 * start login panel,perform login to the system with user's supplied 
	 * details. 
	 * @param frame - the main frame that contains all data about current run of current user e.g.
	 * inserted field panels etc.
	 */
	private static void loginPanel(final MainApplication frame)
	{
		// set login panel
		frame.setSize(438, 435);
		//Set the panel that is about to display
		frame.setContentPane( frame.login );
		
		System.out.println("You are attemting to login to the following:\n");
		System.out.println("Main Server: " + frame.clientControl.getMainServer() );
		System.out.println("Backup Server: " + frame.clientControl.getBackupServer() + "\n");
		
		//if this is the first time you call login add action listeners 
		if ( frame.login.isRunOnce() == false )
		{
			frame.login.setRunOnce( true );
			//Add action listener on "LoginButton"
			frame.login.getLoginButton().addActionListener( new ActionListener() 
				{	
					//Imp ActionListener for getLoginButton
					public void actionPerformed(ActionEvent event) 
					{
						// variables
						String password = new String(frame.login.getPasswordField().getPassword());
						String userName = frame.login.getUserName().getText();
						String loginStatus = null ;
						User user = new User( null, null, userName, password, null);
						
						//Retrieving client details and login status
						loginStatus = frame.clientControl.login(user);
						//successful login
						if (loginStatus.equalsIgnoreCase(LoginClientProtocol.succesfullLogin) )
						{
							//					frame.login.setOriginalUser(user);
							_originalUser = user;
							mainUserPanel(frame);					
						}
						else if (loginStatus.equalsIgnoreCase(LoginClientProtocol.closeApplication) )
						{
							// TODO massage for one more time
							frame.login.getUserName().setText(null);
							frame.login.getPasswordField().setText(null);
							JOptionPane.showMessageDialog(null,
									"The username or password you entered is incorrect.\n Please try again.",
									"Login Error",JOptionPane.ERROR_MESSAGE);
						}
//						else if (loginStatus.equalsIgnoreCase(LoginClientProtocol.closeApplication ) )
//						{
//							JOptionPane.showMessageDialog(null,
//									"You have exceeded the number of tries to login.\n Please Try later ",
//									"Login Error",JOptionPane.ERROR_MESSAGE);
//							System.exit(0);
//						} 
						else if (loginStatus.equalsIgnoreCase(ClientControl.BACKUP_IS_DOWN ) )
						{
							JOptionPane.showMessageDialog(null,
									"Server is down, Please Try later ",
									"Login Error",JOptionPane.ERROR_MESSAGE);
							System.exit(0);
						}
						//client is disconnected
						else if (loginStatus.equalsIgnoreCase(ClientControl.CLIENT_IS_DISCONNECTED ) )
						{
							JOptionPane.showMessageDialog(null,
									CLIENT_DISCONNECTED_ERROR_MESSAGE,
									"Login Error",JOptionPane.ERROR_MESSAGE);
							System.exit(0);
						}
						else
						{
							JOptionPane.showMessageDialog(null,
									"Connection Problem Occured ,Please Try later ",
									"Login Error",JOptionPane.ERROR_MESSAGE);
						}
					}
				}
			);
			//Add Action Listener on RegistrationButton
			frame.login.getRegistrationButton().addActionListener( new ActionListener() 
				{
					//Imp ActionListener for getRegistrationButton
					public void actionPerformed(ActionEvent event) 
					{	
						//set registration panel
						registrationPanel(frame);	
					}
				}
			);
		}
	}
	
	/**
	 * start registration panel,perform registration to the system with user's supplied 
	 * details.
	 * @param frame - the main frame that contains all data about current run of current user e.g.
	 * inserted field panels etc.
	 */
	private static void registrationPanel(final MainApplication frame)
	{
		// set registration panel
		frame.setSize(464, 537);
		frame.setContentPane(frame.regPanel);
		//if this is the first time you call regPanel add action listeners
		if ( frame.regPanel.isRunOnce() == false )
		{
			frame.regPanel.setRunOnce( true );
			
			frame.regPanel.getRegistrationButton().addActionListener(new ActionListener() 
				{			
					public void actionPerformed(ActionEvent event) 
					{
						// variables
						String password = new String(frame.regPanel.getPasswordField().getPassword());
						String firstName = frame.regPanel.getFirstName().getText();
						String lastName = frame.regPanel.getLastName().getText();
						String userName = frame.regPanel.getUserName().getText();
						String Email = frame.regPanel.getEmail().getText();
						String registrationStatus = RegistrationClientProtocol.succesfullRegistration;
						
						if ( (password.isEmpty()) || (firstName.isEmpty()) || (lastName.isEmpty())  || (userName.isEmpty()) )
						{
							JOptionPane.showMessageDialog(null,
									"You Must Enter All the Details ",
									"Error in Details",JOptionPane.ERROR_MESSAGE);
							frame.updatePanel.getEmail().setText(null);
							frame.updatePanel.repaint();
						}
						else if (frame.clientControl.checkValidEmail(Email)== false )
						{
							JOptionPane.showMessageDialog(null,
									"Your Email is Incorrect, Please Retype your Email ",
									"Email Error",JOptionPane.ERROR_MESSAGE);
							frame.updatePanel.getEmail().setText(null);
							frame.updatePanel.repaint();					
						} 
						
						else
						{
							User user = new User(firstName, lastName, userName, password, Email);
							
							//Retrieving client details
							registrationStatus = frame.clientControl.registration(user);
							if (registrationStatus.equalsIgnoreCase(RegistrationClientProtocol.succesfullRegistration) )
							{
								_originalUser = user;
								mainUserPanel(frame);					
							}
							else if (registrationStatus.equalsIgnoreCase(RegistrationClientProtocol.closeApplication) )
							{
								// TODO massage for one more time
								
								JOptionPane.showMessageDialog(null,
										"The username " + frame.regPanel.getUserName().getText() +
										" is  not available.\n Please try again.",
										"Registration Error",JOptionPane.ERROR_MESSAGE);
								frame.regPanel.getUserName().setText(null);
								frame.regPanel.getFirstName().setText(null);
								frame.regPanel.getLastName().setText(null);
								frame.regPanel.getPasswordField().setText(null);
								frame.regPanel.getEmail().setText(null);
							}
//							else if (registrationStatus.equalsIgnoreCase(RegistrationClientProtocol.closeApplication ) )
//							{
//								JOptionPane.showMessageDialog(null,
//										"You have exceeded the number of tries.\n Closing Application ",
//										"Registration Error",JOptionPane.ERROR_MESSAGE);
//								System.exit(0);
//							} 
							else if (registrationStatus.equalsIgnoreCase(ClientControl.BACKUP_IS_DOWN ) )
							{
								JOptionPane.showMessageDialog(null,
										"Server is down, Please Try later ",
										"Registration Error",JOptionPane.ERROR_MESSAGE);
								System.exit(0);
							}
							//client is disconnected
							else if (registrationStatus.equalsIgnoreCase(ClientControl.CLIENT_IS_DISCONNECTED ) )
							{
								JOptionPane.showMessageDialog(null,
										CLIENT_DISCONNECTED_ERROR_MESSAGE,
										"Registration Error",JOptionPane.ERROR_MESSAGE);
								System.exit(0);
							}
							else
							{
								JOptionPane.showMessageDialog(null,
										"Connection Problem Occured ,Please Try later ",
										"Registration Error",JOptionPane.ERROR_MESSAGE);
							}
						}
					}
				}
			);//end Imp of ActionListener getRegistrationButton
			frame.regPanel.getBackButton().addActionListener(new ActionListener() 
				{			
					public void actionPerformed(ActionEvent event) {
						//frame.setSize(frame.login.getSize());
						loginPanel(frame);
					}
				}
			);//end Imp of ActionListener getBackButton
		}
	}
	
	/**
	 * start the main panel of the system.include links to all user panels 
	 * linked panels -  Update User Details <br>
	 * 					Show Purchase History<br>
	 * 					All Local Area Panels<br>
	 * 					Group Coupons Panel<br>
	 * 					Logout<br>
	 * @param frame - the main frame that contains all data about current run of current user e.g.
	 * inserted field panels etc.
	 */
	private static void mainUserPanel(final MainApplication frame)
	{
		// set Main Panel panel
		frame.setSize(584, 575);
		frame.setContentPane( frame.mainPanel );
		
		//if this is the first time you call mainPanel add action listeners
		if ( frame.mainPanel.isRunOnce() == false )
		{
			frame.mainPanel.setRunOnce( true );
			frame.mainPanel.getLogoutButton().addActionListener(new ActionListener() 
				{			
					//Imp action listener for LogoutButton
					public void actionPerformed(ActionEvent event) 
					{	
						frame.clientControl.logout();
						System.exit(0);	
					}
				}
			);
			frame.mainPanel.getHistoryButton().addActionListener(new ActionListener() 
				{			
					//Imp action listener for HistoryButton
					public void actionPerformed(ActionEvent event) 
					{
//						startPurchaseHistoryPanel(frame, true );
						startPurchaseHistoryPanel( frame );
					}
				}
			);
			frame.mainPanel.getUpdateButton().addActionListener(new ActionListener() 
				{	
					//Imp action listener for UpdateButton
					public void actionPerformed(ActionEvent event) 
					{
						updateUserDetailsPanel( frame );
					}
				}
			);
			frame.mainPanel.getSouthButton().addActionListener(new ActionListener() 
				{			
					//Imp action listener for SouthButton
					public void actionPerformed(ActionEvent event) 
					{
//						startLocalPanel(frame, ProgramData.SOUTH, true );
						startLocalPanel(frame, frame.pd.SOUTH, null);
					}
				}
			);
			frame.mainPanel.getCenterButton().addActionListener(new ActionListener() 
				{			
					//Imp action listener for CenterButton
					public void actionPerformed(ActionEvent event) 
					{
//						startLocalPanel(frame, ProgramData.CENTER, true );
						startLocalPanel(frame, frame.pd.CENTER, null);
					}
				}
			);
			frame.mainPanel.getNorthButton().addActionListener(new ActionListener() 
				{
					//Imp action listener for NorthButton
					public void actionPerformed(ActionEvent event) 
					{
//						startLocalPanel(frame, ProgramData.NORTH, true );
						startLocalPanel(frame, frame.pd.NORTH, null);
					}
				}
			);
			frame.mainPanel.getGroupCouponsButton().addActionListener(new ActionListener() 
				{
					//Imp action listener for GroupCoupnButton
					public void actionPerformed(ActionEvent event) 
					{
//						startLocalPanel(frame, ProgramData.GENERAL, true );
						startLocalPanel(frame,frame.pd.GENERAL, null);
					}
				}
			);
		}//end if of "is the first time you call mainPanel add action listeners"
	}
	
	/**
	 * start purchase history panel. retrieving all user purchases in table
	 * @param frame - the main frame that contains all data about current run of current user e.g.
	 * inserted field panels etc.
	 */
	protected static void startPurchaseHistoryPanel(final MainApplication frame)
	{
				
		//final ArrayList<Coupon> couponArrayList = null;
		String[] columNames = {"Product Name","Coupon Price","Purchase Date","Purchase ID",
				};
		//cupon attributes
		 String purchaseDate;
		 int purchaseId;
		 //String userName;
		 String productName;
		 String couponPrice;
		 //int couponId;

		Object [][] data = null ;
		// get data from data base
		ProgramData pd = new ProgramData();
		String userName = frame._originalUser.getUserName();
		ArrayList<PurchaseType> purchaseHistoryArrayList = null;
		
		//rearange data
		int counter = 1 ;
		int numberOfTimesToTryAction = 100 ;
		while (counter<=numberOfTimesToTryAction)
		{
			purchaseHistoryArrayList = frame.clientControl.requestUserHistory(userName);
			if (purchaseHistoryArrayList!=null)
			{
				break;
			}
			else if (frame.clientControl.isServersDown()==true)
			{
				JOptionPane.showMessageDialog(null,
						"Server is down, Please Try later ",
						"System Error",JOptionPane.ERROR_MESSAGE);
				System.exit(0);
			}
			//client is disconnected
			else if ( frame.clientControl.isClientDisconnected() == true ) 
			{
				JOptionPane.showMessageDialog(null,
						CLIENT_DISCONNECTED_ERROR_MESSAGE,
						"System Error",JOptionPane.ERROR_MESSAGE);
				System.exit(0);
			}
			counter = counter + 1;
			
			try
			{
				Thread.sleep(500);
			}
			catch (InterruptedException e)
			{
				System.err.println("MainApplication FAILED TO SLEEP 500 miliseconds, error: " + e.getMessage());
			}
		}
		if (purchaseHistoryArrayList!=null) 
		{
			data = arrangeDataForHistoryTable(purchaseHistoryArrayList);
		}
		else
		{
			JOptionPane.showMessageDialog(null,
					"Server is Busy, Please Try later ",
					"System Error",JOptionPane.ERROR_MESSAGE);	
			mainUserPanel(frame);
		}
		
		// set update panel
		purchaseHistoryPanel = new PurchaseHistoryPanel(columNames, data);
		frame.setSize(frame.purchaseHistoryPanel.getSize());
		frame.setContentPane(frame.purchaseHistoryPanel);
		
		//if this is the first time you call purchaseHistoryPanel add action listeners
		if ( frame.purchaseHistoryPanel.isRunOnce() == false )
		{
			frame.purchaseHistoryPanel.setRunOnce( true );
			frame.purchaseHistoryPanel.getBackButton().addActionListener(new ActionListener() 
				{		
					//Imp of ActionListener for getBackButton 
					public void actionPerformed(ActionEvent event) 
					{
						//frame.setSize(frame.mainPanel.getSize());
						mainUserPanel(frame);
					}
				}
			);
		}
	}
		
	/**
	 * start update User Details Panel panel. display panel for entering all user details and 
	 * Performing user details insertion to data base
	 * @param frame - the main frame that contains all data about current run of current user e.g.
	 * inserted field panels etc.
	 */
	private static void updateUserDetailsPanel(final MainApplication frame)
	{
		// set update panel
		frame.setSize(464, 501);

		//set original user name from login panel
		String originalUserName = _originalUser.getUserName();

		frame.updatePanel.setjTextField2(originalUserName);

		frame.setContentPane(frame.updatePanel);
		
		//if this is the first time you call updatePanel add action listeners
		if ( frame.updatePanel.isRunOnce() == false )
		{
			frame.updatePanel.setRunOnce( true );
			frame.updatePanel.getUpdateButton().addActionListener(new ActionListener() 
				{	
					//Imp ActionListener for getUpdateButton
					public void actionPerformed(ActionEvent event) 
					{
						// variables
						String password = new String(frame.updatePanel.getPasswordField().getPassword());
						String firstName = frame.updatePanel.getFirstName().getText();
						String lastName = frame.updatePanel.getLastName().getText();
						String userName = _originalUser.getUserName();
						String Email = frame.updatePanel.getEmail().getText();
						String updateStatus = null;
						if ( (password.isEmpty()) || (firstName.isEmpty()) || (lastName.isEmpty())  || (userName.isEmpty()) )
						{
							JOptionPane.showMessageDialog(null,
									"You Must Enter All the Details ",
									"Error in Details",JOptionPane.ERROR_MESSAGE);
							frame.updatePanel.getEmail().setText(null);
							frame.updatePanel.repaint();
						}
						else if (frame.clientControl.checkValidEmail(Email)== false )
						{
							JOptionPane.showMessageDialog(null,
									"Your Email is Incorrect, Please Retype your Email ",
									"Email Error",JOptionPane.ERROR_MESSAGE);
							frame.updatePanel.getEmail().setText(null);
							frame.updatePanel.repaint();					
						} 
						else
						{
							User user = new User(firstName, lastName, userName, password,Email);
							User originalUser = _originalUser;
							//Retrieving client details
							updateStatus = frame.clientControl.updateUserDetails(user , originalUser );
							
							if (updateStatus.equalsIgnoreCase(UpdateDetailsClientProtocol.updateSuccesfull) )
							{
								JOptionPane.showMessageDialog(null,
										"Update Was Successful",
										"Update",JOptionPane.INFORMATION_MESSAGE);
								mainUserPanel(frame);					
							}
							else if (updateStatus.equalsIgnoreCase(ClientControl.BACKUP_IS_DOWN ) )
							{
								JOptionPane.showMessageDialog(null,
										"Server is down, Please Try later ",
										"Update Error",JOptionPane.ERROR_MESSAGE);
								System.exit(0);
							}
							//client is disconnected
							else if (updateStatus.equalsIgnoreCase(ClientControl.CLIENT_IS_DISCONNECTED ) )
							{
								JOptionPane.showMessageDialog(null,
										CLIENT_DISCONNECTED_ERROR_MESSAGE,
										"Update Error",JOptionPane.ERROR_MESSAGE);
								System.exit(0);
							}
							else
							{
								JOptionPane.showMessageDialog(null,
										"Communication Problem Occured ,Please Try later ",
										"Update Error",JOptionPane.ERROR_MESSAGE);
								//restart mainUser panel
								mainUserPanel(frame);
								//						System.exit(0);
							}
						} //end else
					}// end actionPerformed(ActionEvent event)
				}//end imp of Action Listener of getUpdateButton
			);
			frame.updatePanel.getBackButton().addActionListener(new ActionListener() 
				{
					//Imp addActionListener for BackButton
					public void actionPerformed(ActionEvent event) 
					{
						//frame.setSize(frame.mainPanel.getSize());
						mainUserPanel(frame);
						System.out.println(event.getClass().getSimpleName() + ": "  + event.getID());
					}
				}//end imp of Action Listener of BackButton
			);
		}
	}//End updateUserPanel

	
	/**
	 * Start coupon details panels by region. Display all coupons at the selected region e.g.north,west and south
	 * Suitable also for the group copons "region" display.  
	 * Supply functionality of filtering - user intrfase for inserting filtering parameters.
	 * @param frame - the main frame that contains all data about current run of current user e.g.
	 * inserted field panels etc.
	 * @param regionID - this is <code>final int</code>. It muse be final since it is sent as a parameter to
	 * the same method afterwards
	 * @param filter - object of type CouponForQuery that include users filtering preference for the coupons that
	 * he like to see. when filter is null all data is retrived.
	 */
	private static void startLocalPanel(final MainApplication frame, final int regionID , CouponForQuery filter)
	{
		//final ArrayList<Coupon> couponArrayList = null;

		//Coupon is normal Coupon from south, north or center
		
		//CouponForQuery filter = new CouponForQuery();
		if ( (regionID != ProgramData.GENERAL) && ( regionID != ProgramData.BACKUP) )
		{
			String[] columNames = {"Category","Business Name","Product Name","Business City",
					"Expiration Date","Discount Amount","Price"};

			Object [][] data = null ;
			// get data from data base
			
			//Receive Object of server by regionID
			correntRegionServer = getServerOfRegion(frame, regionID);
//			int counter = 1;
//			int numberOfTimesToTryAction = 100;
//			
//			//run in loop till we get a Server from Working Server
//			while (counter <= numberOfTimesToTryAction)
//			{
//				correntRegionServer = frame.clientControl.updateRegion(regionID);
//				if (correntRegionServer!=null)
//				{
//					break;
//				}
//				else if (frame.clientControl.isServersDown()==true)
//				{
//					JOptionPane.showMessageDialog(null,
//							"Server is down, Please Try later ",
//							"System Error",JOptionPane.ERROR_MESSAGE);
//					System.exit(0);
//				}
//				counter = counter + 1;
//				try
//				{
//					Thread.sleep(500);
//				}
//				catch (InterruptedException e)
//				{
//					System.err.println("MainApplication FAILED TO SLEEP 500 miliseconds, error: " + e.getMessage());
//				}
//			}
			// In case that after the while loop we didn't get instance of server
			if (correntRegionServer == null)
			{
				JOptionPane.showMessageDialog(null,
						"Server is Busy, Please Try later ",
						"System Error",JOptionPane.ERROR_MESSAGE);
				mainUserPanel(frame);
			}

			//Request Coupons from Working Server
			final ArrayList<Coupon> couponArrayList = frame.clientControl.requestKupons(correntRegionServer, regionID, filter);

			//Check if we didn't receive null Coupons
			boolean isCouponArrayListValid = handleRecievedCouponArrayList(frame, couponArrayList);

			//we received data from Working Server
			if (isCouponArrayListValid == true )
			{
				//re-arrange data
				data = arrangeDataForCouponTable(couponArrayList);
			}
			
//			//reset local panel
//			localPanel = null;

			//Handle Data 
			//set update panel
			localPanel = new LocalPanel(columNames, data,regionID);
			frame.setSize(frame.localPanel.getSize());
			frame.setContentPane(frame.localPanel);

			//if this is the first time you call localPanel with SingleCoupon and add action listeners
			if ( frame.localPanel.isRunOnceSingleCoupon() == false )
			{
				frame.localPanel.setRunOnceSingleCoupon( true );
				final SelectionListener listener = new SelectionListener(frame.localPanel.getJTable0());
				frame.localPanel.getJTable0().getSelectionModel().addListSelectionListener(listener);
				
				frame.localPanel.getPurchaseButton().addActionListener(new ActionListener() 
					{
						//action listener for getPurchaseButton 
						public void actionPerformed(ActionEvent event) 
						{
							int rowNumber = listener.getSelRows();
							
							//Server localServer = frame.clientControl.updateRegion(localPanel.getRegion());
							
							//call purchaseKupon() with false
							if (rowNumber <= -1)
							{
								JOptionPane.showMessageDialog(null,
										"Purchase Failed Please Select Coupon and Try Again",
										"Purchase Error",JOptionPane.ERROR_MESSAGE);
								//TODO Check that this call to the method doesn't make problems
								startLocalPanel(frame, regionID, null);
							}
							int couponID = getCouponID( rowNumber, couponArrayList );
							String purchaseStatus = frame.clientControl.purchaseKupon(couponID,
									frame._originalUser.getUserName(), correntRegionServer, SINGLE_COUPON);
							
							if (purchaseStatus.equalsIgnoreCase(PurchaseKuponClientProtocol.succesfullPurchase ) )
							{
								JOptionPane.showMessageDialog(null,
										"Purchase succeed, Mazal Tov",
										"Purchase",JOptionPane.INFORMATION_MESSAGE);
								//TODO Check that this call to the method doesn't make problems
								startLocalPanel(frame, regionID, null);
							}
							else if (purchaseStatus.equalsIgnoreCase(PurchaseKuponClientProtocol.tryAgain) )
							{
								JOptionPane.showMessageDialog(null,
										"Purchase Failed Please Try Again",
										"Purchase Error",JOptionPane.ERROR_MESSAGE);
							}
							else if (purchaseStatus.equalsIgnoreCase(PurchaseKuponClientProtocol.failedPurchase ) )
							{
								JOptionPane.showMessageDialog(null,
										"Purchase Failed Please Try later ",
										"Purchase Error",JOptionPane.ERROR_MESSAGE);
							} 
							else if (purchaseStatus.equalsIgnoreCase(ClientControl.BACKUP_IS_DOWN ) )
							{
								JOptionPane.showMessageDialog(null,
										"Server is down, Please Try later ",
										"Purchase Error",JOptionPane.ERROR_MESSAGE);
								System.exit(0);
							}
							//client is disconnected
							else if (purchaseStatus.equalsIgnoreCase(ClientControl.CLIENT_IS_DISCONNECTED ) )
							{
								JOptionPane.showMessageDialog(null,
										CLIENT_DISCONNECTED_ERROR_MESSAGE,
										"Purchase Error",JOptionPane.ERROR_MESSAGE);
								System.exit(0);
							}
							else
							{
								JOptionPane.showMessageDialog(null,
										"Connection Problem Occured ,Please Try later ",
										"Purchase Error",JOptionPane.ERROR_MESSAGE);
							}
							//System.out.println("test");
							//frame.localPanel.getRowAt(row);
						}
					}// end Imp for ActionListener of getPurchaseButton
				);
				//this is the first the panel was run and it wasn't run
				//for Group coupon
				if ( frame.localPanel.isRunOnce() == false )
				{
					frame.localPanel.setRunOnce( true );
					frame.localPanel.getBackButton().addActionListener(new ActionListener() 
						{
							//action listener for getBackButton()
							public void actionPerformed(ActionEvent event) 
							{
								//frame.setSize(frame.mainPanel.getSize());
								mainUserPanel(frame);
							}
						}
					);
					
					frame.localPanel.getGoButton().addActionListener(new ActionListener() 
					{
						//action listene for getGoButton()
						public void actionPerformed(ActionEvent event) 
						{
							CouponForQuery tempfilter = buildQueryObject(frame.localPanel,frame);
							//frame.setSize(frame.mainPanel.getSize());
							startLocalPanel(frame, regionID, tempfilter);
						}
					}
				);
				}
			}//end if "is this the first time you localPanel with SingleCoupon?" 
		}//end if "Coupon is normal Coupon from south, north or center ?"
		
		//Coupon is GroupCoupon from General
		else
		{
			String[] columNames = {"Category","Business Name","Product Name","Business City",
					"Expiration Date","Discount Amount","Price","Amount Bought","Fixed Amount"};

			Object [][] data = null ;
			// get data from data base

			int regionOfServerWithGroupCoupons;
			//First, we need to try and ask GroupCoupons from MAIN SERVER
			if (regionID == ProgramData.BACKUP)
			{
				regionOfServerWithGroupCoupons = ProgramData.GENERAL;
			}
			else
			{
				regionOfServerWithGroupCoupons = regionID;
			}
			
			//Receive Object of server by regionID
			correntRegionServer = getServerOfRegion(frame, regionOfServerWithGroupCoupons);
//			int counter = 1;
//			int numberOfTimesToTryAction = 100;
//			//run in loop till we get a "server" from Working Server
//			while (counter <= numberOfTimesToTryAction)
//			{
//				//regionID can be either 3=GENERAL or 4=BACKUP
//				correntRegionServer = frame.clientControl.updateRegion( regionOfServerWithGroupCoupons );
//				if (correntRegionServer!=null)
//				{
//					break;
//				}
//				else if (frame.clientControl.isServersDown()==true)
//				{
//					JOptionPane.showMessageDialog(null,
//							"Server is down, Please Try later ",
//							"System Error",JOptionPane.ERROR_MESSAGE);
//					System.exit(0);
//				}
//				counter = counter + 1;
//				try
//				{
//					Thread.sleep(500);
//				}
//				catch (InterruptedException e)
//				{
//					System.err.println("MainApplication FAILED TO SLEEP 500 miliseconds, error: " + e.getMessage());
//				}
//			}
			if (correntRegionServer == null)
			{
				JOptionPane.showMessageDialog(null,
						"Server is Busy, Please Try later ",
						"System Error",JOptionPane.ERROR_MESSAGE);
				mainUserPanel(frame);
			}
			final ArrayList<GroupCoupon> couponArrayList = frame.clientControl.requestMultipleKupons(correntRegionServer, regionOfServerWithGroupCoupons ,filter);

			//Check if we didn't receive null Coupons
			boolean isCouponArrayListValid = handleRecievedCouponArrayList(frame, couponArrayList);
			
			//we received data from Working Server
			if (isCouponArrayListValid == true)
			{
				//re-arrange data
				data = arrangeDataForGroupCouponTable( couponArrayList );
			}

			// set update panel
			localPanel = new LocalPanel(columNames, data, regionOfServerWithGroupCoupons);
			frame.setSize(frame.localPanel.getSize());
			frame.setContentPane(frame.localPanel);

			if ( frame.localPanel.isRunOnceGroupCoupon() == false )
			{
				frame.localPanel.setRunOnceGroupCoupon( true );
				final SelectionListener listener = new SelectionListener(frame.localPanel.getJTable0());
				frame.localPanel.getJTable0().getSelectionModel().addListSelectionListener(listener);
				
				//action listener for PurchaseButton
				frame.localPanel.getPurchaseButton().addActionListener(new ActionListener() 
					{
						//imp action listener for getPurchaseButton			
						public void actionPerformed(ActionEvent event) 
						{
							int row = listener.getSelRows();
							
							//Server localServer = frame.clientControl.updateRegion(localPanel.getRegion());
							
							if (row <= -1)
							{
								JOptionPane.showMessageDialog(null,
										"Purchase Failed Please Select Coupon and Try Again",
										"Purchase Error",JOptionPane.ERROR_MESSAGE);
								//TODO Check that this call to the method doesn't make problems
								startLocalPanel(frame, regionID, null);
							}
							
							int couponID = getGroupCouponID( row, couponArrayList );
							String purchaseStatus = frame.clientControl.purchaseKupon(couponID, frame._originalUser.getUserName(), correntRegionServer, GROUP_COUPON);
							//System.out.println("test");
							//frame.localPanel.getRowAt(row);
							if (purchaseStatus.equalsIgnoreCase(PurchaseKuponClientProtocol.succesfullPurchase ) )
							{
								JOptionPane.showMessageDialog(null,
										"Purchase succeed, Mazal Tov",
										"Purchase",JOptionPane.INFORMATION_MESSAGE);	
								//TODO Check that this call to the method doesn't make problems
								startLocalPanel(frame, ProgramData.GENERAL, null);
							}
							else if (purchaseStatus.equalsIgnoreCase(PurchaseKuponClientProtocol.tryAgain) )
							{
								JOptionPane.showMessageDialog(null,
										"Purchase Failed Please Try Again",
										"Purchase Error",JOptionPane.ERROR_MESSAGE);
							}
							else if (purchaseStatus.equalsIgnoreCase(PurchaseKuponClientProtocol.DataBaseError) )
							{
								JOptionPane.showMessageDialog(null,
										"Purchase Failed Due Data Base Error",
										"Purchase Error",JOptionPane.ERROR_MESSAGE);
							}
							else if (purchaseStatus.equalsIgnoreCase(PurchaseKuponClientProtocol.failedPurchase ) )
							{
								JOptionPane.showMessageDialog(null,
										"Purchase Failed - The coupon had run out",
										"Purchase Error",JOptionPane.ERROR_MESSAGE);
							} 
							else if (purchaseStatus.equalsIgnoreCase(ClientControl.BACKUP_IS_DOWN ) )
							{
								JOptionPane.showMessageDialog(null,
										"Server is down, Please Try later ",
										"Purchase Error",JOptionPane.ERROR_MESSAGE);
								System.exit(0);
							}
							else
							{
								JOptionPane.showMessageDialog(null,
										"Connection Problem Occured ,Please Try later ",
										"Purchase Error",JOptionPane.ERROR_MESSAGE);
							}
							//System.out.println("test");
							//frame.localPanel.getRowAt(row);
						}
					}// End imp action listener for getPurchaseButton
				);
				//this is the first the panel was run and it wasn't run
				//for single coupon
				if ( frame.localPanel.isRunOnce() == false )
				{
					frame.localPanel.setRunOnce( true );
					frame.localPanel.getBackButton().addActionListener(new ActionListener() 
						{
							//action listene for BackButton()
							public void actionPerformed(ActionEvent event) 
							{
								//frame.setSize(frame.mainPanel.getSize());
								mainUserPanel(frame);
							}
						}
					);
					
					frame.localPanel.getGoButton().addActionListener(new ActionListener() 
					{
						//action listene for getGoButton()
						public void actionPerformed(ActionEvent event) 
						{
							CouponForQuery tempfilter = buildQueryObject(frame.localPanel,frame);
							//frame.setSize(frame.mainPanel.getSize());
							startLocalPanel(frame, regionID, tempfilter);
						}
					}
				);
				}
			}//end if of isRunOnceGroupCoupon()
		}//end if Coupon is GroupCoupon from General
	}
	
	/**
	 * This function builds CouponForQuery object from data inserted in LocalPanel ata the filtering section
	 * @param localPanel - the panel that holds all user filtering preferences.
	 * @param frame - the main frame that contains all data about current run of current user e.g.
	 * inserted field panels etc.
	 * @return filter - CouponForQuery object that contain all selected filtering preferences
	 */
	protected static CouponForQuery buildQueryObject(LocalPanel localPanel, final MainApplication frame)
	{
		CouponForQuery filter = new CouponForQuery();
		String category = (String) localPanel.getCategoryComboBox0().getSelectedItem();
		if (category == "All Categories") 
		{
			filter.setCategory(-1);
		}
		else
		{
			filter.setCategory(ProgramData.categoryNamestrToint(category));
		}
		
		String strPrice = localPanel.getPriceFromField().getText();
		if (strPrice != null &&  !strPrice.equals(""))
		{
			int price;
			try
			{
				price = Integer.parseInt(strPrice);
				filter.setCouponPriceDownLimit(price);
			}
			catch (NumberFormatException e)
			{
				JOptionPane.showMessageDialog(null,
						"Price Down Limit Format is Incorrect ",
						"Error in Details",JOptionPane.ERROR_MESSAGE);
				frame.localPanel.getPriceFromField().setText(null);
				frame.localPanel.repaint();
				e.printStackTrace();
			}
		}
		
		strPrice = localPanel.getPriceToField().getText();
		if (strPrice != null &&  !strPrice.equals(""))
		{
			int price;
			try
			{
				price = Integer.parseInt(strPrice);
				filter.setCouponPriceUpLimit(price);
			}
			catch (NumberFormatException e)
			{
				
				JOptionPane.showMessageDialog(null,
						"Price Up Limit Format is Incorrect ",
						"Error in Details",JOptionPane.ERROR_MESSAGE);
				frame.localPanel.getPriceToField().setText(null);
				frame.localPanel.repaint();
				
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		
		String strDate = localPanel.getDateFromField().getText();
		if (strDate != null &&  !strDate.equals(""))
		{
			
			try 
			{ 
				String str_date = localPanel.getDateFromField().getText();
				DateFormat formatter ; 
				Date date ; 
				formatter = new SimpleDateFormat("dd-MM-yyyy");
				date = (Date)formatter.parse(str_date);  
				filter.setExpirationDateDownLimit(date);
				//System.out.println("Today is " +date );
			} 
			catch (ParseException e)
			{
				JOptionPane.showMessageDialog(null,
						"Date Down Limit Format is Incorrect ",
						"Error in Details",JOptionPane.ERROR_MESSAGE);
				frame.localPanel.getDateFromField().setText(null);
				frame.localPanel.repaint();
				
				System.out.println("Exception :"+e); 
			}  
			 			
		}
		
		strDate = localPanel.getDateToField().getText();
		if (strDate != null &&  !strDate.equals(""))
		{
			
			try 
			{ 
				String str_date = localPanel.getDateToField().getText();
				DateFormat formatter ; 
				Date date ; 
				formatter = new SimpleDateFormat("dd-MM-yyyy");
				date = (Date)formatter.parse(str_date);  
				filter.setExpirationDateUpLimit(date);
				//System.out.println("Today is " +date );
			} 
			catch (ParseException e)
			{
				JOptionPane.showMessageDialog(null,
						"Date Up Limit Format is Incorrect ",
						"Error in Details",JOptionPane.ERROR_MESSAGE);
				frame.localPanel.getDateToField().setText(null);
				frame.localPanel.repaint();
				
				System.out.println("Exception :"+e);  
			}  
			 			
		}
		
		return filter;
	}

	/**
	 * This function arrange purchase history objects array and convert it to format
	 * that is suitable for Jtable display 
	 * @param purchaseHistoryArrayList list of objects from type PurchaseType
	 * @return PurchaseData of type Object
	 */
	private static Object[][] arrangeDataForHistoryTable(
			ArrayList<PurchaseType> purchaseHistoryArrayList)
	{
		
		 //ProgramData pd = new ProgramData();
		 int PurchaseNumber = purchaseHistoryArrayList.size();
		 Object PurchaseData[][] = new Object[0][0];
		 PurchaseData = (Object[][])resizeArray(PurchaseData,PurchaseNumber);
		 
		 int tempPurchaseNumber = 0 ;
		 
		//cupon attributes
		 String purchaseDate;
		 int purchaseId;
		 //String userName;
		 String productName;
		 String couponPrice;
		 //int couponId;
		 
		 
		 for (int i=0; i<PurchaseNumber; i++) {
		     if (PurchaseData[i] == null)
		    	 PurchaseData[i] = new Object[4];
		      else PurchaseData[i] = (Object[])resizeArray(PurchaseData[i],30); }
		 
		//change cupon attributes to string 
		for ( PurchaseType purchase:purchaseHistoryArrayList )
		{
			
			PurchaseData[tempPurchaseNumber][0] = purchase.getProductName();
			PurchaseData[tempPurchaseNumber][1] = purchase.getCouponPrice();
			PurchaseData[tempPurchaseNumber][2] = purchase.getPurchaseDate();
			PurchaseData[tempPurchaseNumber][3] = purchase.getPurchaseId();
			
			tempPurchaseNumber = tempPurchaseNumber + 1; 
		
		}
		return PurchaseData;
		
	}
	
//	/**
//	 * @param frame
//	 * @param someValue
//	 * @author Sapir
//	 */
//	@SuppressWarnings("unused")
//	private static void startPurchaseHistoryPanel(final MainApplication frame, boolean someValue)
//	{
//		//This should fix the bug that on second click on button the application perform the action twice
//		//and on the third click it performs it three times
//		
//		//get values of the right static variables
//		int entranceCounter = getStartPurchaseHistoryPanelEntranceCounter(  );
//		int displayCounter = getStartPurchaseHistoryPanelDisplayCounter(  );
//		if ( entranceCounter == displayCounter )
//		{
//			//init MainApplication.startPurchaseHistoryPanelEntranceCounter after successful entrance
//			entranceCounter = 0;
//			//Increase the number times the function run and does nothing
//			displayCounter++;
//			
//			//Call startPurchaseHistoryPanel function that perform a REAL Action
//			startPurchaseHistoryPanel( frame );
//		}
//		else
//		{
//			//Increase the number of times the function has tried to enter
//			entranceCounter++;	
//		}
//		//set values of the right static variables
//		setStartPurchaseHistoryPanelEntranceCounter( entranceCounter );
//		setStartPurchaseHistoryPanelDisplayCounter( displayCounter );
//	}
//	
//	/**
//	 * setter for static variable startHistoryPanelDisplayCounter
//	 * @param displayCounter - the static variable
//	 * @author Sapir
//	 */
//	private static void setStartPurchaseHistoryPanelDisplayCounter(
//			int displayCounter)
//	{
//		MainApplication.startHistoryPanelDisplayCounter = displayCounter; 
//	}
//
//	/**
//	 * setter for static variable startPurchaseHistoryPanelEntranceCounter
//	 * @param entranceCounter - the static variable
//	 * @author Sapir
//	 */
//	private static void setStartPurchaseHistoryPanelEntranceCounter(
//			int entranceCounter)
//	{
//		MainApplication.startHistoryPanelEntranceCounter = entranceCounter;
//	}
//
//	/**
//	 * getter for static variable startHistoryPanelDisplayCounter
//	 * @author Sapir
//	 */
//	private static int getStartPurchaseHistoryPanelDisplayCounter()
//	{
//		return MainApplication.startHistoryPanelDisplayCounter;
//	}
//
//	/**
//	 * getter for static variable startHistoryPanelEntranceCounter
//	 * @author Sapir
//	 */
//	private static int getStartPurchaseHistoryPanelEntranceCounter()
//	{
//		return MainApplication.startHistoryPanelEntranceCounter;
//	}

//	/**
//	 * Due to unknown reason the method:<br> <code>startLocalPanel(final MainApplication frame, int regionID)</code> :<br>
//	 * run in her first call 1 times, in its second call 2 times, in its third call 3 times etc...<br>
//	 * To prevent this behavior we call <strong>THIS METHOD</strong>.<br>
//	 * It checks if the number of the times the method as tried to perform its action <code>EntranceCounter</code> equals to the number of times
//	 * it runs before the last run <code>DisplayCounter</code>.<br>
//	 * If both value are equals, then the method performs its action
//	 * @param frame - frame object
//	 * @param regionID - The region of server, see {@link ProgramData} for different regions
//	 * @param someValue - some type of variable to create overloading of methods
//	 * @author Sapir<br>
//	 */
//	@SuppressWarnings("unused")
//	private static void startLocalPanel(final MainApplication frame, int regionID, boolean someValue)
//	{
//		//This should fix the bug that on second click on button the application perform the action twice
//		//and on the third click it performs it three times
//		
//		//get values of the right static variables
//		int EntranceCounter = getStartLocalPanelEntranceCounter( regionID );
//		int DisplayCounter = getStartLocalPanelDisplayCounter( regionID );
//		if ( EntranceCounter == DisplayCounter )
//		{
//			//init MainApplication.startLocalPanelEntranceCounter after successful entrance
//			EntranceCounter = 0;
//			//Increase the number times the function run and does nothing
//			DisplayCounter++;
//			
//			//Call startLocalPanel function that perform a REAL Action
//			startLocalPanel(frame, regionID, null);
//		}
//		else
//		{
//			//Increase the number of times the function has tried to enter
//			EntranceCounter++;	
//		}
//		//set values of the right static variables
//		setStartLocalPanelEntranceCounter( regionID, EntranceCounter );
//		setStartLocalPanelDisplayCounter( regionID, DisplayCounter );
//		
//	}
//			
//	/**
//	 * setter for static variable StartLocalPanel<strong>_REGION_</strong>DisplayCounter
//	 * @param regionID - The region of server, see {@link ProgramData} for different regions
//	 * @param displayCounter - the static variable that corresponds to regionID
//	 * @author Sapir
//	 */
//	private static void setStartLocalPanelDisplayCounter(int regionID,
//			int displayCounter)
//	{
//		switch (regionID)
//		{
//		case ProgramData.NORTH:
//			MainApplication.startLocalPanelNorthDisplayCounter = displayCounter;
//			break;
//			
//		case ProgramData.CENTER:
//			MainApplication.startLocalPanelCenterDisplayCounter = displayCounter;
//			break;
//			
//		case ProgramData.SOUTH:
//			MainApplication.startLocalPanelSouthDisplayCounter = displayCounter;
//			break;
//			
//		case ProgramData.GENERAL:
//			MainApplication.startLocalPanelGeneralDisplayCounter = displayCounter;
//			break;
//
//		default:
//			break;
//		}
//	}
//	
//	/**
//	 * setter for static variable StartLocalPanel<strong>_REGION_</strong>EntranceCounter
//	 * @param regionID - The region of server, see {@link ProgramData} for different regions
//	 * @param entranceCounter - the static variable that corresponds to regionID
//	 * @author Sapir
//	 */
//	private static void setStartLocalPanelEntranceCounter(int regionID,
//			int entranceCounter)
//	{
//		switch (regionID)
//		{
//		case ProgramData.NORTH:
//			MainApplication.startLocalPanelNorthEntranceCounter = entranceCounter;
//			break;
//			
//		case ProgramData.CENTER:
//			MainApplication.startLocalPanelCenterEntranceCounter = entranceCounter;
//			break;
//			
//		case ProgramData.SOUTH:
//			MainApplication.startLocalPanelSouthEntranceCounter = entranceCounter;
//			break;
//			
//		case ProgramData.GENERAL:
//			MainApplication.startLocalPanelGeneralEntranceCounter = entranceCounter;
//			break;
//
//		default:
//			break;
//		}
//	}
//
//	/**
//	 * getter for static variable StartLocalPanel<strong>_REGION_</strong>DisplayCounter
//	 * @param regionID - The region of server, see {@link ProgramData} for different regions
//	 * @author Sapir
//	 */
//	private static int getStartLocalPanelDisplayCounter(int regionID)
//	{
//		switch (regionID)
//		{
//		case ProgramData.NORTH:
//			return MainApplication.startLocalPanelNorthDisplayCounter;
//			
//		case ProgramData.CENTER:
//			return MainApplication.startLocalPanelCenterDisplayCounter;
//			
//		case ProgramData.SOUTH:
//			return MainApplication.startLocalPanelSouthDisplayCounter;
//			
//		case ProgramData.GENERAL:
//			return MainApplication.startLocalPanelGeneralDisplayCounter;
//
//		default:
//			return -1;
//		}
//	}
//
//	/**
//	 * getter for static variable StartLocalPanel<strong>_REGION_</strong>EntranceCounter
//	 * @param regionID - The region of server, see {@link ProgramData} for different regions
//	 * @author Sapir
//	 */
//	private static int getStartLocalPanelEntranceCounter(int regionID)
//	{
//		switch (regionID)
//			{
//			case ProgramData.NORTH:
//				return MainApplication.startLocalPanelNorthEntranceCounter;
//				
//			case ProgramData.CENTER:
//				return MainApplication.startLocalPanelCenterEntranceCounter;
//				
//			case ProgramData.SOUTH:
//				return MainApplication.startLocalPanelSouthEntranceCounter;
//				
//			case ProgramData.GENERAL:
//				return MainApplication.startLocalPanelGeneralEntranceCounter;
//
//			default:
//				return -1;
//			}
//	}
		
	/**
	 * this function retrieving coupon id number
	 * @param row - the row in table or the place at couponArrList of the desired coupon
	 * @param couponArrList - array of coupons that that can be purchased 
	 * @return coupon ID
	 */
	protected static  int getGroupCouponID(int row,ArrayList<GroupCoupon> couponArrList)
	{
		GroupCoupon coupon = couponArrList.get(row);
		return coupon.getId();
	}

	//The method return Object[][] for ArrayList<GroupCoupon>
	/**
	 * This function arrange group coupons objects and convert it to Data For Group Coupon Table.the convertion to format
	 * that is suitable for Jtable display
	 * @param couponArrayList - list of objects from type GroupCoupon
	 * @return couponData - array of type object that sutibale for displaying with Jtable
	 */
	private static Object [][] arrangeDataForGroupCouponTable(ArrayList<GroupCoupon> couponArrayList)
	{
		int couponNumber = couponArrayList.size();
		Object couponData[][] = new Object[0][0];
		couponData = (Object[][])resizeArray(couponData,couponNumber);

		int tempCouponNumber = 0 ;

		//cupon attributes
		int state;
		String scategory;
		String sregion;
		String sid;
		String sbusinessName;
		String sproductName;
		String sbusinessCity;
		String sexpirationDate;
		String sdiscountAmount;
		String scouponPrice;
		String amountBought;
		String fixedAmount;

		for (int i=0; i<couponNumber; i++) {
			if (couponData[i] == null)
				couponData[i] = new Object[9];
			else couponData[i] = (Object[])resizeArray(couponData[i],30); }

		//change cupon attributes to string 
		for ( GroupCoupon coupon:couponArrayList )
		{

			scategory = ProgramData.categoryToString(coupon.getCategory());
			couponData[tempCouponNumber][0] = scategory;

			sbusinessName = coupon.getBusinessName();
			couponData[tempCouponNumber][1] = sbusinessName;

			sproductName = coupon.getProductName();
			couponData[tempCouponNumber][2] = sproductName;

			sbusinessCity = coupon.getBusinessCity();
			couponData[tempCouponNumber][3] = sbusinessCity;

			sexpirationDate = coupon.getExpirationDate();
			couponData[tempCouponNumber][4] = sexpirationDate;

			sdiscountAmount = Integer.toString(coupon.getDiscountAmount());
			couponData[tempCouponNumber][5] = sdiscountAmount;

			scouponPrice = Integer.toString(coupon.getCouponPrice());
			couponData[tempCouponNumber][6] = scouponPrice;

			amountBought = Integer.toString(coupon.getAmountBought());
			couponData[tempCouponNumber][7] = amountBought;

			fixedAmount = Integer.toString(coupon.getFixedAmount());
			couponData[tempCouponNumber][8] = fixedAmount;

			tempCouponNumber = tempCouponNumber + 1; 
		}
		return couponData;
	}

	/**
	 * this function retrieving coupon id number
	 * @param row - the row in table or the place at couponArrList of the desired coupon
	 * @param couponArrList - array of coupons that that can be purchased 
	 * @return coupon ID
	 */
	protected static int getCouponID(int row,ArrayList<Coupon> couponArrList)
	{
		Coupon coupon = couponArrList.get(row);
		return coupon.getId();
	}
	//The method return Object[][] for ArrayList<Coupon>
	/**
	 * This function arrange coupons objects and convert it to Data For Coupon Table.the convertion to format
	 * that is suitable for Jtable display
	 * @param couponArrayList
	 * @return couponData - array of type object that sutibale for displaying with Jtable
	 */
	private static Object [][] arrangeDataForCouponTable(ArrayList<Coupon> couponArrayList)
	{
		 ProgramData pd = new ProgramData();
		 int couponNumber = couponArrayList.size();
		 Object couponData[][] = new Object[0][0];
		 couponData = (Object[][])resizeArray(couponData,couponNumber);
		 
		 int tempCouponNumber = 0 ;
		 
		//cupon attributes
		 int state;
		 String scategory;
		 String sregion;
		 String sid;
		 String sbusinessName;
		 String sproductName;
		 String sbusinessCity;
		 String sexpirationDate;
		 String sdiscountAmount;
		 String scouponPrice;
		 
		 for (int i=0; i<couponNumber; i++) {
		     if (couponData[i] == null)
		    	 couponData[i] = new Object[7];
		      else couponData[i] = (Object[])resizeArray(couponData[i],30); }
		 
		//change cupon attributes to string 
		for ( Coupon coupon:couponArrayList )
		{
			
			scategory = pd.categoryToString(coupon.getCategory());
			couponData[tempCouponNumber][0] = scategory;
			
			sbusinessName = coupon.getBusinessName();
			couponData[tempCouponNumber][1] = sbusinessName;
			
			sproductName = coupon.getProductName();
			couponData[tempCouponNumber][2] = sproductName;
			
			sbusinessCity = coupon.getBusinessCity();
			couponData[tempCouponNumber][3] = sbusinessCity;
			
			sexpirationDate = coupon.getExpirationDate();
			couponData[tempCouponNumber][4] = sexpirationDate;
			
			sdiscountAmount = Integer.toString(coupon.getDiscountAmount());
			couponData[tempCouponNumber][5] = sdiscountAmount;
			
			scouponPrice = Integer.toString(coupon.getCouponPrice());
			couponData[tempCouponNumber][6] = scouponPrice;
			
			tempCouponNumber = tempCouponNumber + 1; 
		}
		return couponData;
	}
	
		
	/**
	* Reallocates an array with a new size, and copies the contents<BR>
	* of the old array to the new array.
	* @param oldArray  the old array, to be reallocated.
	* @param newSize   the new array size.
	* @return          A new array with the same contents.
	*/
	private static Object resizeArray (Object oldArray, int newSize) 
	{
		//make some dynamic creation of an array 
		int oldSize = java.lang.reflect.Array.getLength( oldArray );
		Class elementType = oldArray.getClass().getComponentType();
		Object newArray = java.lang.reflect.Array.newInstance( elementType, newSize );
		//check in need to copy elements and how many elements from old array to new array
		int preserveLength = Math.min( oldSize, newSize );
		if (preserveLength > 0)
		{
			System.arraycopy (oldArray,0,newArray,0,preserveLength);
		}
		return newArray; 
	}

	
	/**
	 * @param frame - UI frame {@link MainApplication}
	 * @param couponArrayList - <code>ArrayList</code> of type {@link Coupon} or {@link GroupCoupon}
	 * @return <code>true</code> - if received ArrayList from server.<br>
	 * <code>false</code> - if didn't receive ArrayList from server.<br>
	 * @author Sapir
	 */
	private static boolean handleRecievedCouponArrayList(final MainApplication frame, final ArrayList<?> couponArrayList)
	{
//******************************************************************************************************************//
//										Start of DEBUG ONLY															//
//******************************************************************************************************************//
//		System.err.println("\nWe are in: " + MainApplication.getFrames().getClass().getSimpleName());
//		if (couponArrayList != null)
//		{
//			if (couponArrayList.isEmpty() == false)
//			{
//				System.err.println("It runs on Coupons of type: " + couponArrayList.get(0).getClass().getSimpleName() );
//			}
//		}
//******************************************************************************************************************//
//										End of DEBUG ONLY															//
//******************************************************************************************************************//
		
		//didn't receive data from Working Server 
		if (couponArrayList == null)
		{
			//both main & backup servers are down
			if ( frame.clientControl.isServersDown() == true )
			{
				//exit application
				JOptionPane.showMessageDialog(null,
						"Server is down, Please Try later ",
						"System Error",JOptionPane.ERROR_MESSAGE);
				System.exit(0);
			}
			//Client is disconnected
			else if ( frame.clientControl.isClientDisconnected() == true )
			{
				JOptionPane.showMessageDialog(null,
						CLIENT_DISCONNECTED_ERROR_MESSAGE,
						"System Error",JOptionPane.ERROR_MESSAGE);
				System.exit(0);
			}
			//both main & backup servers are up
			else
			{
				//return to main panel
				JOptionPane.showMessageDialog(null,
						"Server is Busy, Please Try later ",
						"System Error",JOptionPane.ERROR_MESSAGE);	
				mainUserPanel(frame);	
			}
		}
		//we received data from Working Server
		return true;
	}
	
	
	/**
	 * @param frame - UI frame {@link MainApplication}
	 * @param serverRegionID - <code>int</code> that represents the region we works with
	 * @return object of type {@link Server} that is server to get service from
	 * @author Sapir
	 */
	private static Server getServerOfRegion(MainApplication frame ,int serverRegionID)
	{
//******************************************************************************************************************//
//										Start of DEBUG ONLY															//
//******************************************************************************************************************//
		System.err.println("\nWe are in: getServerOfRegion() method" );
		System.err.println("We try to get server of region: " + serverRegionID + "\n" );
//******************************************************************************************************************//
//										End of DEBUG ONLY															//
//******************************************************************************************************************//
		int counter = 1;
		int numberOfTimesToTryAction = 100;
		Server serverToReturn = null;
		
		//run in loop till we get a "server" from Working Server
		while (counter <= numberOfTimesToTryAction)
		{
			serverToReturn = frame.clientControl.updateRegion( serverRegionID );
			if (serverToReturn != null)
			{
				break;
			}
			//happens when BOTH servers are down
			else if (frame.clientControl.isServersDown() == true)
			{
				JOptionPane.showMessageDialog(null,
						"Server is down, Please Try later ",
						"System Error",JOptionPane.ERROR_MESSAGE);
				System.exit(0);
			}
			//happens when client is disconnected
			else if ( frame.clientControl.isClientDisconnected() == true )
			{
				JOptionPane.showMessageDialog(null,
						CLIENT_DISCONNECTED_ERROR_MESSAGE ,
						"System Error",JOptionPane.ERROR_MESSAGE);
				System.exit(0);
			}
			counter++;
			try
			{
				Thread.sleep(500);
			}
			catch (InterruptedException e)
			{
				System.err.println("MainApplication FAILED TO SLEEP 500 miliseconds, error: " + e.getMessage());
			}
		}
//******************************************************************************************************************//
//										Start of DEBUG ONLY															//
//******************************************************************************************************************//
System.err.println("\nWe return server: " + serverToReturn.getAdress() );
System.err.println("Its region is: " + serverToReturn.getRegion() + "\n" );
//******************************************************************************************************************//
//										End of DEBUG ONLY															//
//******************************************************************************************************************//
		return serverToReturn;
	}
	
	/**
	 * Main entry of the class.
	 * Note: This class is only created so that you can easily preview the result at runtime.
	 * It is not expected to be managed by the designer.
	 * You can modify it as you like.
	 */
	public static void main(String[] args)
	{
		installLnF();
		SwingUtilities.invokeLater(new Runnable()
		{
			//This is implimentation of run() method for an object of type Runnable
			@Override
			public void run()
			{
				MainApplication frame = new MainApplication();
				frame.setDefaultCloseOperation(MainApplication.EXIT_ON_CLOSE);
				frame.setTitle("CoupMaster");
				frame.getContentPane().setPreferredSize(frame.getSize());
				frame.pack();
				frame.setLocationRelativeTo(null);
				frame.setVisible(true);
				
				commercials = new ComercialThread(frame);
				commercials.start();
				loginPanel(frame);
			}
		});
	}

}
